// graphql-express.js
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
var { graphql, buildSchema } = require('graphql');
const { v4: uuidv4 } = require('uuid');
const fs = require('fs');
const jwt = require('jsonwebtoken');
const secret = 'zwq-secret-key';

function getInfo (token) {
  const decoded = jwt.verify(token, secret);
  return decoded
}

// 使用 GraphQL schema language 构建一个 schema
// 任何导致写入的操作都应该通过mutation显式发送
var schema = buildSchema(`
  scalar DateTime
  type DeletionStatus {
    status: Boolean!
  }
  # 参数对象必须用input定义
  input CreateArticleInput {
    title: String!
    body: String!
    tagList: [String!]
  }
  input UpdateArticleInput {
    title: String!
    body: String!
  }
  type Article {
    slug: String!
    title: String!
    description: String!
    body: String!
    tagList: [String!]!
    createdAt: DateTime!
    updatedAt: DateTime!
    favorited: Boolean!
    favoritesCount: Int!
    author: User!
  }
  type Comment {
    id: ID!
    body: String!
    createdAt: DateTime!
    updatedAt: DateTime!
    author: User!
    article: Article!
  }
  type User {
    email: String!
    username: String!
    bio: String
    image: String
    
    favorites: [Article!]!
    articles: [Article!]!
    comments: [Comment!]!
    token: String
    following: Boolean
  }

  
  # 1. query查询 Int!表示数据字段不能为空 [String!]!数据元素不能为空
  # article(id: ID, title: String)是查询参数
  type Query {
    test: String,
    slug: String,
    content: String,
    name: String,
    age: Int!
    hello: String
    user: User
    listArticles: [Article]
    getArticle(slug: String): Article
    getCommentsFromAnArticle(slug: String): [Comment]
    updateUser(email: String, bio: String, image: String): User
    tags: [String]
    login(email: String, password: String): User
    getProfile(username: String): User
    feedArticles: [Article]
    getCurrentUser: User
  }
  # 2. 修改入口点
  type Mutation {
    register(username: String, email: String, password: String): User
    favoriteArticle(slug: String): Article
    unFavoriteArticle(slug: String): Article
    addComment(slug: String, content: String): Comment
    deleteComment(slug: String, id: String): Comment
    createArticle(article: CreateArticleInput): Article
    updateArticle(id: ID!,article: UpdateArticleInput): Article
    deleteArticle(id: ID!): DeletionStatus
    createAtricle(title: String, description: String, body: String, tagList: String): Article
    updateAtricle(slug: String, title: String, description: String, body: String): Article
    deleteAtricle(slug: String): Article
    followUser(username: String): User
    unFollowUser(username: String): User
  }
`);



// 根节点为每个 API 入口端点提供一个 resolver 函数
var root = {
  test() {
    console.log(getInfo('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InpoYWduc2FuMjU3QHFxLmNvbSIsInBhc3N3b3JkIjoiMTIzNDU2IiwiaWF0IjoxNjg3MTU0MjkxLCJleHAiOjE2ODcxNTc4OTF9.aqKFm0NpOVQE2l9QvGjnDSEQl4FEIYKwU-xvF3jSyOY'))
    return '123'
  },
  listArticles: () => { 
    // 别名用法
    // {
    //     empireHero: articles {
    //       title
    //       body
    //     }
    //     jediHero: articles {
    //       favoritesCount
    //     }
    //   }
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    // 查询所有文章
    return articlesList
  },
  // 这个要过滤下条件 ?tag=AngularJS  ?author=jake  ?favorited=jake 
  // ?limit=20 ?offset=0
  getArticle: ({ slug }) => {
    console.log(slug)
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => item.slug === slug)
    if(index !== -1) {
      return articlesList[index]
    } else {
      throw new Error('Get Article Fail');
    }
    // 根据 slug 查询文章
  },
  createAtricle: ({ title, description, body, tagList }) => {
    const now = new Date();
    const localString = now.toLocaleString();
    let article = {
      slug: uuidv4().replace(/-/g, ''),
      title, description, body, tagList,
      favoritesCount: 0,
      comment: [],
      favoritedBy: [],
      createdAt: localString,
      updatedAt: localString,
      "author": {
          "username": "zhangsan257",
          "bio": null,
          "image": "https://api.realworld.io/images/smiley-cyrus.jpeg",
          "following": false
      }
    }
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    articlesList.push(article)
    fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
    return article
  },
  updateAtricle: ({ slug, title, description, body }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => item.slug === slug)
    if(index !== -1) {
      console.log(title, description, body)
      title && (articlesList[index].title = title)
      description && (articlesList[index].description = description)
      body && (articlesList[index].body = body)
      console.log(articlesList[index].title)
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return articlesList[index]
    } else {
      throw new Error('Update Article Fail');
    }
  },
  deleteAtricle: ({ slug }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => item.slug === slug)
    if(index !== -1) {
      let article = JSON.parse(JSON.stringify(articlesList[index]))
      articlesList.splice(index, 1)
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return article
    } else {
      throw new Error('Delete Article Fail');
    }
  },
  getCommentsFromAnArticle: ({ slug }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => slug === item.slug)
    if(index !==  -1 && articlesList[index].comment) {
      return articlesList[index].comment
    } else {
      throw new Error('Get Comment Fail');
    }   
    // 查询所有评论
  },
  addComment: ({ slug, content }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => slug === item.slug)
    const now = new Date();
    const localString = now.toLocaleString();
    if(index !==  -1) {
      if(!articlesList[index].comment) articlesList[index].comment = []
      let commentObj = {
        id: articlesList[index].comment.length + 85759,
        createdAt: localString,
        updatedAt: localString,
        body: content,
        author: {
          "username": "xiaoqinag007",
          "bio": null,
          "image": "https://api.realworld.io/images/smiley-cyrus.jpeg",
          "following": false
        }
      }
      let comment = articlesList[index].comment
      comment.push(commentObj)
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return commentObj
    } else {
      throw new Error('Add Comment Fail');
    }
  },
  deleteComment: ({ slug, id }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => slug === item.slug)
    if(index !==  -1) {
      if(!articlesList[index].comment) articlesList[index].comment = []
      let idx = articlesList[index].comment.findIndex(itm => itm.id == id)
      if(idx != -1) {
        let obj = JSON.parse(JSON.stringify(articlesList[index].comment[idx]))
        articlesList[index].comment.splice(idx, 1)
        fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
        return obj
      } else {
        throw new Error('Delete Comment Fail');
      }
    } else {
      throw new Error('Delete Comment Fail');
    }
  },
  user: () => {
    // 查询所有用户
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let userList = jsonData.userList
    return userList
  },
  getCurrentUser: () => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let userList = jsonData.userList
    return userList[0]
  },
  updateUser: ({ email, bio, image }) => {
    // zhangsan257
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let userList = jsonData.userList
    let index = userList.findIndex(item => item.username === 'zhangsan257')
    if(index !== -1) {
      email && (userList[index].email = email)
      bio && (userList[index].bio = bio)
      image && (userList[index].image = image)
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return userList[index]
    } else {
      throw new Error('Update Article Fail');
    }
  },
  tags: () => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let tags = jsonData.tags
    return tags
  },
  login: ({ email, password }) => { 
    try {
      const data = fs.readFileSync('userData.json', 'utf8');
      let userList = JSON.parse(data).userList;
      let index = userList.findIndex(item => email === item.email)
      const token = jwt.sign({ email, password }, secret, { expiresIn: '1h' });
      if(index !== -1) {
        return {
          "email": email,
          "username": userList[index].username,
          "bio": null,
          "image": userList[index].image,
          "token": token
        }
      } else {
        throw new Error('User not found');
      }
      console.log(userList);
    } catch (err) {
      console.error(err);
    }
  },
  register: ({ username, email, password }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    const jsonData = JSON.parse(data);
    jsonData.userList.push({ username, email, password, image: 'https://api.realworld.io/images/smiley-cyrus.jpeg' })
    fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
    const token = jwt.sign({ email, password }, secret, { expiresIn: '1h' });
    return {
      "email": email,
      "username": username,
      "bio": null,
      "image": "https://api.realworld.io/images/smiley-cyrus.jpeg",
      "token": token
    }
  },
  getProfile: ({ username }) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let userList = JSON.parse(data).userList;
    let index = userList.findIndex(item => username === item.username)
    if(index !== -1) {
      return {
        "username": userList[index].username,
        "bio": null,
        "image": userList[index].username,
        "following": userList[index].following ? userList[index].following : false
      }
    } else {
      throw new Error('User not found');
    }

  },
  followUser: ({ username }) => {
    // 当前是zhangsan257
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data)
    let userList = jsonData.userList;
    let index = userList.findIndex(item => username === item.username)
    if(index !== -1) {
      if(!userList[index].followList) userList[index].followList = []
      let idx = userList[index].followList.findIndex(itm => itm.username == username)
      if(idx !== -1) {
        throw new Error('已关注');
      } else {
        let user = {
          "username": "zhangsan257",
          "bio": null,
          "image": "https://api.realworld.io/images/smiley-cyrus.jpeg",
          "following": true
        }
        userList[index].followList.push(user)
        fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
        return user
      }
    } else {
      throw new Error('User not found');
    }
  },
  unFollowUser: ({ username }) => { 
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data)
    let userList = jsonData.userList;
    let index = userList.findIndex(item => username === item.username)
    if(index !== -1) {
      if(!userList[index].followList) userList[index].followList = []
      let idx = userList[index].followList.findIndex(itm => itm.username == username)
      if(idx !== -1) {
        throw new Error('未关注当前用户');
      } else {
        let user = {
          "username": "zhangsan257",
          "bio": null,
          "image": "https://api.realworld.io/images/smiley-cyrus.jpeg",
          "following": false
        }
        userList[index].followList.splice(idx, 1)
        fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
        return user
      }
    } else {
      throw new Error('User not found');
    }
  },
  feedArticles: () => { 
    // 应该是同一个作者发布的信息
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    // Anah Benešová
    let list = articlesList.filter(item => item?.author?.username == 'Anah Benešová') || []
    return list
  },
  // addCommentsToAnArticle: ({ slug }) => { },
  favoriteArticle: ({slug}) => {
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => slug === item.slug)
    if(index !==  -1) {
      if(!articlesList[index].favoritedBy) articlesList[index].favoritedBy = []
      articlesList[index].favoritedBy.push({
        "id": 0,
        "email": "gerome123@me",
        "username": "Gerome123",
        "password": "$2a$10$p599IEkBem34A2p0EZb.ce/YJzycchtTkuUmAYdNAl95MR3PeLk3a",
        "image": "https://api.realworld.io/images/demo-avatar.png",
        "bio": "Hello followers",
        "demo": true
      })
      articlesList[index].favoritesCount++
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return articlesList[index]
    } else {
      throw new Error('Article not found');
    }
  },
  unFavoriteArticle: ({slug}) => {  
    const data = fs.readFileSync('userData.json', 'utf8');
    let jsonData = JSON.parse(data);
    let articlesList = jsonData.articlesList
    let index = articlesList.findIndex(item => slug === item.slug)
    if(index !==  -1) {
      if(!articlesList[index].favoritedBy) articlesList[index].favoritedBy = []
      // 默认是 gerome@me 用户登录了
      let idx = articlesList[index].favoritedBy.findIndex(itm => itm.email == 'gerome@me')
      if(idx!== -1) {
        articlesList[index].favoritedBy.splice(idx, 1)
        articlesList[index].favoritesCount--
      } else {
        console.log(idx)
      }
      fs.writeFileSync('userData.json', JSON.stringify(jsonData, null, 2), 'utf8');
      return articlesList[index]
    } else {
      throw new Error('Article not found');
    }
  }
};


const app = express();
const cors = require('cors')
app.use(cors())

app.use(
  '/graphql',
  graphqlHTTP({
    schema: schema,
    graphiql: true,
    rootValue: root,
    customFormatErrorFn: (error) => ({
      message: error.message,
      // code: error.originalError instanceof Error ? 'INTERNAL_SERVER_ERROR' : error.originalError.code,
      data: error.originalError?.data,
    }),
  }),
);

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Server error');
});

app.listen(4000, () => {
  console.log('http://localhost:4000')
});
